9.5 Список Задач + SQLite + Interface + DI
7 из 7 шагов пройдено

 Список Задач + SQLite + Interface + DI

➡️Ссылка на репозиторий с кодом этого урока

Подход 1: "Чистый" SQL

Этот подход дает полный контроль над запросом. Вы пишете SQL-команду в виде строки и передаете ее на выполнение. Для защиты от SQL-инъекций параметры передаются отдельно в виде списка.

Добавляем в проект новый файл lib/services/sqlite_service.dart

Файл lib/services/sqlite_service.dart

import 'package:path/path.dart';  
import 'package:sqflite/sqflite.dart';  
import '../services/storage_interface.dart';  
import '../models/task.dart';  
  
class SqliteService implements IStorageService {  
  // Приватная переменная для хранения экземпляра БД  
  Database? _database;  
  
  static const _dbName = 'tasks_database.db'; // Название файла с бд  
  static const _tasksTableName = 'tasks'; // 1 таблица для списка задач  
  static const _settingsTableName = 'settings'; // 2 таблица для настроек  
  
  // Геттер для получения экземпляра БД.
  // Если он еще не создан, инициализирует его.
  Future<Database> get database async {  
    if (_database != null) {  
      return _database!;  
    }  
    _database = await _initDB();  
    return _database!;  
  }  
  
  /// Инициализация базы данных  
  Future<Database> _initDB() async {  
    // Получаем путь к каталогу для баз данных по умолчанию  
    // Для Android это data/data/<package_name>/databases
	final dbPath = await getDatabasesPath();  
    // Соединяем путь и имя файла БД  
    final path = join(dbPath, _dbName);  
  
    return await openDatabase(  
      path,  
      version: 1,  
      // onCreate выполняется 1 раз  
      onCreate: (db, version) async {  
        // Выполняем SQL-запрос для создания таблицы  
        await db.execute('''    
			CREATE TABLE $_tasksTableName(    
	            id INTEGER PRIMARY KEY AUTOINCREMENT,  
	            text TEXT NOT NULL,
				isDone INTEGER NOT NULL
			)
			''');  
        // Выполняем SQL-запрос для создания таблицы  
        await db.execute('''    
			CREATE TABLE $_settingsTableName(    
	            key TEXT PRIMARY KEY,  
	            value INTEGER
			)''');  
      },  
    );  
  }  
  
  /// Создание новой задачи  
  @override  
  Future<Task> createTask(String text) async {  
    final db = await database;  
  
    // Используем INSERT для добавления новой записи в таблицу  
    // Метод rawInsert возвращает ID новой записи
	final newId = await db.rawInsert(  
      'INSERT INTO $_tasksTableName(text, isDone) VALUES(?, ?)',  
      [text, 0],  
    );  
  
    // Создаём и возвращаем объект Task с ID из базы данных.  
    return Task(id: newId, text: text, isDone: false);  
  }  
  
  /// Получение всех задач  
  @override  
  Future<List<Task>> getAllTasks() async {  
    final db = await database;  
    // Используем SELECT для получения ВСЕХ записей из таблицы  
    final List<Map<String, dynamic>> allTasks = await db.rawQuery(  
      'SELECT * FROM $_tasksTableName',  
    );  
  
    // Преобразуем список Map в список объектов Task и возвращаем его  
    return List.generate(allTasks.length, (i) {  
      return Task(  
        id: allTasks[i]['id'],  
        text: allTasks[i]['text'],  
        isDone: allTasks[i]['isDone'] == 1,  
      );  
    });  
  }  
  
  /// Обновление задачи  
  @override  
  Future<void> updateTask(Task task) async {  
    final db = await database;  
  
    // Используем UPDATE для обновления записи по её ID  
	await db.rawUpdate(  
	  'UPDATE $_tasksTableName SET isDone = ? WHERE id = ?',  
	  [task.isDone ? 1 : 0, task.id],  
	);
  }  
  
  /// Удаление задачи  
  @override  
  Future<void> deleteTask(int id) async {  
    final db = await database;  
  
    // Используем DELETE для удаления записи по её ID  
    await db.rawDelete('DELETE FROM $_tasksTableName WHERE id = ?', [id]);  
  }  
  
  /// Получение цветовой темы  
  @override  
  Future<bool> getThemeMode() async {  
    final db = await database;  
  
    final List<Map<String, dynamic>> settings = await db.rawQuery(  
      'SELECT value FROM $_settingsTableName WHERE key = ?',  
      ['isDarkMode'],  
    );  
  
    if (settings.isNotEmpty) {  
      // В таблице настроек будет только одна запись, то достаём её через first  
      // Если будет 1 == 1 то вернётся значение true, иначе false
	  return settings.first['value'] == 1;  
    }  
    return false;  
  }  
  
  /// Сохранение цветовой темы  
  @override  
  Future<void> saveThemeMode(bool isDarkMode) async {  
    final db = await database;  
  
    await db.rawInsert(  
      'INSERT OR REPLACE INTO $_settingsTableName (key, value) VALUES (?, ?)',  
      ['isDarkMode', isDarkMode ? 1 : 0],  
    );  
  }  
}

Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий